前面提到 Auto Scaling 的概念:
流量增加
│
▼
增加 Backend
流量降低後:
減少 Backend
進入 Kubernetes 之後,Backend 通常已經變成 Pod。
例如目前:
Deployment
│
├── Pod 1
├── Pod 2
└── Pod 3
也就是:
replicas = 3
如果使用者突然增加,三個 Pod 的 CPU 使用率開始升高:
Pod 1 → CPU 85%
Pod 2 → CPU 90%
Pod 3 → CPU 88%
我們可能希望 Kubernetes 自動增加:
Pod 4
Pod 5
Pod 6
讓更多 Pod 一起處理 Request。
這就是 Kubernetes Auto Scaling 的其中一個核心概念。
Kubernetes 裡非常常見的一種自動擴縮方式叫做:
Horizontal Pod Autoscaler
簡稱:
HPA
Horizontal 的意思就是:
水平增加 Pod 數量
例如原本:
Pod Pod Pod
變成:
Pod Pod Pod Pod Pod Pod
而不是把單一 Pod 的 CPU:
1 Core
直接升級成:
8 Core
後者比較接近 Vertical Scaling。
最簡單的方式是根據 CPU 使用率。
例如我們設定:
最低 Pod 數量:2
最高 Pod 數量:10
目標 CPU:60%
現在有:
3 Pods
平均 CPU:
35%
那可能繼續維持三個 Pod。
但是流量增加後:
Pod 1 → 85%
Pod 2 → 80%
Pod 3 → 88%
平均 CPU 明顯高於:
60%
HPA 就可能開始增加 Pod。
例如:
3 Pods
│
▼
5 Pods
新增 Pod 後,Request 可以被分散。
Service
│
┌─────────┼─────────┐
▼ ▼ ▼
Pod 1 Pod 2 Pod 3
▼ ▼
Pod 4 Pod 5
如果流量降低,CPU 長時間下降:
Pod 平均 CPU = 20%
HPA 又可以把:
5 Pods
減少成:
2 Pods
除了 CPU,Auto Scaling 還可以根據其他 Metrics。
例如:
CPU
Memory
Request 數量
Queue Length
Custom Metrics
例如一個背景工作系統:
Queue
│
├── 100 jobs
├── 500 jobs
└── 10,000 jobs
可能就不是看 CPU,而是根據 Queue 長度增加 Worker Pod。
例如:
Queue < 100
→ 2 Workers
Queue = 1,000
→ 5 Workers
Queue = 10,000
→ 20 Workers
所以 Auto Scaling 真正的概念是:
根據系統負載指標,自動調整運算資源。
前面我們寫過:
replicas: 3
代表 Deployment 希望維持:
3 個 Pod
但是使用 HPA 之後,Pod 數量就可以動態調整。
例如:
HPA
│
▼
Deployment
│
▼
Pods
HPA 會根據 Metrics 調整 Deployment 的 replica 數量。
概念上就是:
Metrics
│
▼
HPA
│
▼
replicas
│
▼
Deployment
│
▼
Pods
因此:
HPA 決定要幾個
Deployment 負責維持這些 Pod
HPA 必須知道:
Pod CPU 是多少?
Memory 是多少?
所以 Kubernetes 需要 Metrics 資料。
常見架構可以理解為:
Pod
│
▼
Metrics
│
▼
HPA
例如:
Pod 1 CPU = 70%
Pod 2 CPU = 75%
Pod 3 CPU = 80%
HPA 根據這些數據判斷:
需要 Scale Out
於是增加 Pod。
當資源增加:
3 Pods
│
▼
6 Pods
通常稱為:
Scale Out
也就是水平擴充。
當流量降低:
6 Pods
│
▼
3 Pods
稱為:
Scale In
也就是水平縮減。
所以 Auto Scaling 其實就是不停根據負載:
Scale Out
↑
↓
Scale In
保持適當的 Pod 數量。
假設 Cluster 目前:
Node 1
Node 2
Node 3
每一台 Node 都已經快滿了。
例如:
Node 1
CPU 95%
Node 2
CPU 92%
Node 3
CPU 90%
HPA 此時說:
我要增加 5 個 Pod
但是 Kubernetes 發現:
沒有 Node 有足夠資源
結果新的 Pod 可能會停在:
Pending
也就是:
想建立 Pod
但是沒有機器可以放
這代表只增加 Pod 還不夠。
這時就會需要另一層 Auto Scaling:
Cluster Autoscaler
HPA 解決的是:
Pod 不夠
→ 增加 Pod
Cluster Autoscaler 解決的是:
Node 不夠
→ 增加 Node
例如:
HPA
│
▼
我要 10 個 Pod
但是 Cluster:
Node 1 滿了
Node 2 滿了
Node 3 滿了
新的 Pod 無法被 Scheduling。
Cluster Autoscaler 發現:
有 Pod 因資源不足而 Pending
於是增加:
Node 4
Node 5
然後 Scheduler 就可以把新的 Pod 放進去。
假設原本:
Service
│
┌──────┼──────┐
▼ ▼ ▼
Pod 1 Pod 2 Pod 3
突然有大量使用者。
第一步:
Request 增加
接著:
Pod CPU 增加
HPA 發現:
CPU > Target
於是:
3 Pods
│
▼
8 Pods
但是 Node 資源不足:
Pod 7 → Pending
Pod 8 → Pending
Cluster Autoscaler 發現後:
Node 1
Node 2
擴充成:
Node 1
Node 2
Node 3
Scheduler 再把 Pending Pod 放進 Node 3。
完整流程:
Traffic ↑
│
▼
CPU ↑
│
▼
HPA
│
▼
Pods ↑
│
▼
Node 資源不足
│
▼
Cluster Autoscaler
│
▼
Nodes ↑
這才是一個完整的水平 Auto Scaling。
這兩件事情非常容易混在一起。
可以簡單記:
HPA
→ 增減 Pod
而:
Cluster Autoscaler
→ 增減 Node
例如:
Kubernetes Cluster
Node 1
├── Pod
├── Pod
└── Pod
Node 2
├── Pod
└── Pod
HPA 做的是:
Pod + Pod + Pod
Cluster Autoscaler 做的是:
Node 3
除了 Horizontal Pod Autoscaler,還有另一個概念:
Vertical Pod Autoscaler
簡稱:
VPA
它不是增加 Pod 數量。
而是調整 Pod 所需要的:
CPU
Memory
例如原本:
Pod
CPU Request = 500m
Memory = 512Mi
系統觀察後發現:
Memory 長期需要 1GB
可能就調整成:
CPU Request = 500m
Memory = 1Gi
所以:
HPA
→ Pod 數量
VPA
→ 單個 Pod 資源
前面說 Scheduler 會決定:
Pod 放哪一台 Node
但是 Scheduler 要知道:
這個 Pod 需要多少 CPU?
需要多少 Memory?
因此 Deployment 通常會設定:
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
其中:
requests
可以理解成:
這個 Pod 至少希望獲得多少資源。
而:
limits
則表示:
這個 Pod 最多可以使用多少資源。
Scheduler 可以根據 requests 判斷:
Node 1 還有 1 CPU
這個 Pod 需要 0.5 CPU
→ 可以放
假設我們設定:
CPU Request = 500m
而實際使用:
CPU = 400m
那麼使用率大約就是:
400 / 500
= 80%
如果 HPA Target:
60%
那麼:
80% > 60%
HPA 就可能判斷需要增加 Pod。
所以:
Resource Request
如果亂設,Auto Scaling 的判斷也可能變得不合理。
現在回頭看前面的 Stateless Backend。
假設 HPA:
Pod 3
│
▼
Pod 10
這代表突然新增七個 Backend。
如果 Backend 是 Stateful:
使用者 Session
只存在 Pod 1 Memory
新的 Pod:
Pod 4
Pod 5
Pod 6
...
全部不知道這些 Session。
那 Auto Scaling 就會變得非常麻煩。
但是如果 Backend 是 Stateless:
Session → Redis
Business Data → Database
File → Object Storage
那新的 Pod 只需要:
啟動 Application
連 Redis
連 Database
就可以立刻開始服務。
這就是:
Stateless
│
▼
Pod 可以隨時建立
│
▼
HPA
│
▼
Auto Scaling
為什麼彼此這麼密切相關。
Auto Scaling 不只是增加。
還會:
Pod 10
│
▼
Pod 3
也就是刪掉七個 Pod。
如果重要資料存在其中某個 Pod:
Pod 8
└── User Cart
Pod 8 被刪:
User Cart X
資料就消失。
但如果:
Shopping Cart → Redis
即使 Pod 8 被刪掉:
Pod 8 X
Redis ✓
下一個 Request 到 Pod 2:
Pod 2
│
▼
Redis
│
▼
Cart Data
仍然可以繼續處理。
所以 Auto Scaling 的核心前提之一就是:
Pod 應該盡量可以被建立,也可以被銷毀。
這裡也要注意一個現實問題。
假設流量突然暴增:
100 Request/s
│
▼
10,000 Request/s
HPA 不會瞬間產生大量可用 Backend。
新的 Pod 還需要:
建立 Pod
│
▼
Pull Docker Image
│
▼
Start Container
│
▼
Application 啟動
│
▼
Health Check
│
▼
Ready
所以 Auto Scaling 有延遲。
如果還需要增加 Node:
建立 VM
│
▼
加入 Cluster
│
▼
Pull Image
│
▼
Start Pod
時間又會更長。
因此 Auto Scaling 並不是:
流量暴增
→ 馬上無限資源
而是需要合理設計:
minimum replicas
maximum replicas
CPU target
startup time
readiness check
scale policy
假設平常流量很低。
如果允許:
replicas = 0
那第一個使用者進來時可能需要等待 Backend 啟動。
對一般 Web API 來說,通常會希望至少維持:
2 或 3 個 Pod
例如:
minReplicas: 3
maxReplicas: 20
平常:
3 Pods
流量增加:
8 Pods
尖峰:
20 Pods
流量降低:
3 Pods
但不會低於:
3
這樣系統可以保持基本的可用能力。
為什麼不能直接:
maxReplicas = 無限
因為 Backend 增加後,後面的系統不一定撐得住。
例如:
10 Backend
每台建立:
20 Database Connections
總共:
200 Connections
如果 Auto Scaling 變成:
100 Backend
就可能產生:
2,000 DB Connections
Database 反而先被打爆。
因此不能只想:
Backend 不夠
→ 無限增加 Backend
而要看整個系統:
Frontend
│
Load Balancer
│
Backend Pods
│
Redis
│
Database
│
Third-party API
每一層都有自己的 Capacity。
例如:
3 Pods
每秒總共對 DB 發:
300 Queries
HPA 擴充到:
30 Pods
可能變成:
3,000 Queries/s
Backend 看起來變快了。
但是:
Database CPU 100%
結果整個系統仍然變慢。
因此真正的 Auto Scaling 不只是:
看 Backend CPU
還要觀察:
Database
Redis
Queue
External API
Network
Connection Pool
這也是大型系統的 Scaling 比單純增加 Pod 複雜很多的原因。
整個流程可以整理成:
Internet
│
▼
Ingress
│
▼
Service
│
▼
Backend Pods
│
┌────────────┴────────────┐
▼ ▼
Redis Database
當流量增加:
Traffic ↑
│
▼
Pod CPU ↑
│
▼
Metrics
│
▼
HPA
│
▼
Pod replicas ↑
如果 Node 不夠:
Pod Pending
│
▼
Cluster Autoscaler
│
▼
Node ↑
然後:
Scheduler
│
▼
把新的 Pod 放進新 Node
完整循環:
Traffic
│
▼
Metrics
│
▼
HPA
│
▼
Deployment
│
▼
More Pods
│
▼
Scheduler
│
├── Node 有空間
│ │
│ ▼
│ 啟動 Pod
│
└── Node 沒空間
│
▼
Cluster Autoscaler
│
▼
More Nodes
│
▼
啟動 Pod
一開始我們只有:
一台 Server
Nginx
Frontend
FastAPI
Database
後來:
Frontend
Backend
分離部署。
Backend 再增加:
Load Balancer
Backend 1
Backend 2
Backend 3
為了共享狀態:
Redis
Backend 改成:
Stateless
為了快速建立 Backend:
Docker Image
大量 Container 需要管理:
Kubernetes
Kubernetes 裡:
Node
Pod
Deployment
Service
Ingress
最後再加入:
HPA
Cluster Autoscaler
就變成:
Internet
│
▼
Ingress
│
▼
Service
│
▼
┌── Backend Pods ──┐
│ │
▼ ▼
Redis Database
▲
│
HPA
│
調整 Pod 數量
+
Cluster Autoscaler
│
調整 Node 數量
因此 Kubernetes Auto Scaling 真正的意義就是:
根據系統負載,自動調整 Application Pod 的數量;當底層機器資源也不足時,再進一步調整 Node 數量。
而 Stateless Backend 讓這些 Pod 可以安全地被建立、替換與刪除,這也是前面所有架構設計最後能串在一起的原因。